package hallows;
import javax.xml.transform.TransformerFactory
import javax.xml.transform.Transformer
import javax.xml.transform.stream.StreamResult
import javax.xml.transform.stream.StreamSource
import javax.xml.validation.SchemaFactory
import javax.xml.validation.Schema
import javax.xml.validation.Validator
import javax.xml.XMLConstants
import groovy.util.slurpersupport.GPathResult
import org.xml.sax.SAXException

public class WsdlIngester {
	
	// take in a string, and if it is a valid URL,
	// see if it points to a valid WSDL 1.1 or 2.0 file.
	// If so, then return a Map of the contents of the WSDL file.
	def readWsdl(String wsdlUrlString) {
		try {
			def String wsdl= wsdlUrlString.toUrl().getText()
			if (validate_11(wsdl)) { return readWsdl_11(wsdl) }
			else if (validate_20(wsdl)) { return readWsdl_20(wsdl) }
			else { return ['error':'invalid WSDL file'] }
		}
		catch (MalformedURLException e) { return ['error':'invalid URL'] }
	}
	
	// See if a document (string) is a valid WSDL 1.1 file.
	// If so, return true.  Otherwise, false.
	def validate_11(String wsdl) {
		try {
			def SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
			def Schema schema = factory.newSchema(new File('lib/wsdl11.xsd'))
			def Validator validator = schema.newValidator()
			validator.validate(new StreamSource(new StringReader(wsdl)))
			return true
		}
		catch (IllegalArgumentException iae) { return false }
		catch (SAXException se) { println se; return false }
		catch (IOException ie) { println ie; return false }
		catch (NullPointerException npe) { println npe; return false }
	}
	
	// See if a document (string) is a valid WSDL 2.0 file.
	// If so, return true.  Otherwise, false.
	def validate_20(String wsdl) {
		try {
			def SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI)
			def Schema schema = factory.newSchema(new File('lib/wsdl20.xsd'))
			def Validator validator = schema.newValidator()
			validator.validate(new StreamSource(new StringReader(wsdl)))
			return true
		}
		catch (IllegalArgumentException iae) { return false }
		catch (SAXException se) { println se; return false }
		catch (IOException ie) { println ie; return false }
		catch (NullPointerException npe) { println npe; return false }
	}
	
	// Read in a valid WSDL 1.1 file, and convert to WSDL 2.0.
	// Return the parse Map of the WSDL file.
	def readWsdl_11(String wsdlString) {
		def definitions= new XmlSlurper().parseText(wsdlString).declareNamespace(wsdl: 'http://schemas.xmlsoap.org/wsdl/')
		def String service= definitions.@targetNamespace.text()
		def List operations= []
		def List inputs= []
		def List outputs= []
		definitions.'wsdl:portType'.each { pt ->
			pt.'wsdl:operation'.each { op ->
				operations << "${service}/${op.@name.text()}"
				op.'wsdl:input'.each { inp ->
					inputs << ["${service}/${op.@name.text()}":"${service}/${inp.@messageLabel.text()}"]
				}
				op.'wsdl:output'.each { out ->
					outputs << ["{service}/${op.@name.text()}":"${service}/${out.@messageLabel.text()}"]
				}
			}
		}
		return ['service':service, 'operations':operations]
	}

	
	// Read in a valid WSDL 2.0 file and
	// return a map relating the service to its interface operations.
	def readWsdl_20(String wsdlString) {
		def wsdl= new XmlSlurper().parseText(wsdlString).declareNamespace(wsdl: 'http://www.w3.org/ns/wsdl')
		def String service= wsdl.@targetNamespace.text()
		def List operations= []
		def List inputs= []
		def List outputs= []
		wsdl.'wsdl:interface'.each { i ->
			i.'wsdl:operation'.each { op ->
				operations << op.@name.text()
				op.'wsdl:input'.each { inp ->
					inputs << ["${op.@name.text()}":inp.@messageLabel.text()]
				}
				op.'wsdl:output'.each { out ->
					outputs << ["${op.@name.text()}":out.@messageLabel.text()]
				}
			}
		}
		return ['service':service, 'operations':operations, 'inputs':inputs, 'outputs':outputs]
	}
}
